package cn.edu.fzu.homemaking.wallet.service.impl;

import cn.edu.fzu.homemaking.common.SessionConstant;
import cn.edu.fzu.homemaking.wallet.cache.UserCache;
import cn.edu.fzu.homemaking.wallet.domain.dto.CompanyUser;
import cn.edu.fzu.homemaking.wallet.domain.dto.User;
import cn.edu.fzu.homemaking.wallet.domain.entity.MoneyWater;
import cn.edu.fzu.homemaking.wallet.domain.entity.Wallet;
import cn.edu.fzu.homemaking.wallet.domain.enums.ChargeModeEnum;
import cn.edu.fzu.homemaking.exception.ServiceException;
import cn.edu.fzu.homemaking.wallet.mapper.WalletMapper;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import cn.edu.fzu.homemaking.wallet.service.WalletService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

@Aspect
@Component
public class WalletServiceImpl implements WalletService {

    private static final String    TEMPLATE_WATER = "template_water";

    private static final String    RECHARGE_DESC  = "充值";

    @Resource
    private WalletMapper           walletMapper;

    @Resource
    private UserCache              userCache;

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override

    public Wallet getByUserId(Long userId) {
        Wallet wallet = walletMapper.getByUserId(userId);
        if (wallet == null) {
            walletMapper.insert(userId);
            wallet = walletMapper.getByUserId(userId);
        }
        return wallet;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(User from, String fromUserType, Long to, BigDecimal money, String description) {

        Long fromId = null;
        Long toId = null;
        String fromName = null;
        String toName = null;
        if (SessionConstant.USER.equals(fromUserType)) {
            fromId = from.getId();
            fromName = userCache.getCustomerName(from.getCustomerId());

            CompanyUser companyUser = userCache.getCompanyUser(to);
            toId = companyUser.getId();
            toName = companyUser.getCompany().getName();
        } else {
            fromId = from.getId();
            fromName = from.getCompany().getName();

            toId = to;
            toName = userCache.getCustomerName(toId);
        }

        Wallet fromWallet = getByUserId(fromId);
        if (fromWallet.getSurplus().compareTo(money) < 0) {
            throw new ServiceException("余额不足");
        }

        Wallet toWallet = getByUserId(toId);
        if (toWallet == null) {
            throw new ServiceException("被转账人账户不存在");
        }
        //减少转账人金额
        walletMapper.updateMoney(fromId, money.negate());
        //增加被转账人金额
        walletMapper.updateMoney(toId, money);
        //生成转账人流水表
        walletMapper.insertWater(fromId, toId, toName, fromWallet.getSurplus(), money, ChargeModeEnum.OUT, description);
        walletMapper.insertWaterTemplate(TEMPLATE_WATER + fromId, toId, toName, fromWallet.getSurplus(), money,
                ChargeModeEnum.OUT, description);
        //生成被转账人流水表
        walletMapper.insertWater(toId, fromId, fromName, toWallet.getSurplus(), money, ChargeModeEnum.IN, description);
        if (walletMapper.tableExist(TEMPLATE_WATER + toId)) {
            walletMapper.insertWaterTemplate(TEMPLATE_WATER + toId, fromId, fromName, toWallet.getSurplus(), money,
                    ChargeModeEnum.IN, description);
        }
    }


    @Override
    public MoneyWater getWaterDetail(Long userId, Long id) {
        return walletMapper.getWaterTemplateById(TEMPLATE_WATER + userId, id);
    }


    @Override
    @Transactional
    public void recharge(User user, BigDecimal money) {
        Wallet wallet = getByUserId(user.getId());
        walletMapper.updateMoney(user.getId(), money);
        walletMapper.insertWater(user.getId(), user.getId(), user.getName(), wallet.getSurplus(), money,
                ChargeModeEnum.IN, RECHARGE_DESC);
        walletMapper.insertWaterTemplate(TEMPLATE_WATER + user.getId(), user.getId(), user.getName(),
                wallet.getSurplus(), money, ChargeModeEnum.IN, RECHARGE_DESC);
    }


    @Override
    public void initWater(Long userId) {
        String tableName = TEMPLATE_WATER + userId;
        walletMapper.createTemplate(tableName);
        threadPoolTaskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                Long id = null;
                int count = 0;
                while (true) {
                    walletMapper.initTemplate(tableName, userId, count, id);
                    Long newId = walletMapper.getMinIdFromTemplate(TEMPLATE_WATER + userId);
                    if (Objects.equals(id, newId)) {
                        break;
                    }
                    id = newId;
                    count += 1000;
                }
            }
        });
    }


    @Override
    public void dropTemplate(Long userId) {
        walletMapper.dropTemplate(TEMPLATE_WATER + userId);
    }


    @Override
    public List<MoneyWater> listWaterTemplate(Long userId, ChargeModeEnum chargeMode) {
        return walletMapper.listWaterTemplate(TEMPLATE_WATER + userId, chargeMode);
    }

}
